#include "constanttable.h"
#include "jbfile.h"
#include <math.h>

bool ConstantEntry::equal(ConstantEntry * entry)
{
	if (m_tag==entry->m_tag)
	{
		return isEqual(entry);
	}
	else
		return false;
}


void ConstantEntry::write(JBFile * file)
{
	file->write(m_tag);
	writeData(file);
}

ConstantEntry::~ConstantEntry()
{
}




ConstantTable::ConstantTable()
{
}

unsigned short ConstantTable::addConstant(ConstantEntry * data)
{
  unsigned short pos=m_pool.size();
  for (unsigned int i=0;i<m_pool.size() && pos==m_pool.size();i++)
  {
	if (m_pool[i]->equal(data))
		pos=i;
  }
  if (pos==m_pool.size())
	  m_pool.push_back(data);
  else
	  delete data;
  return pos+1;
}


void ConstantTable::write(JBFile * file)
{
	file->write((unsigned short)(m_pool.size()+1));
	for (unsigned int i=0;i<m_pool.size();i++)
	{
		m_pool[i]->write(file);
	}
}
ConstantTable::~ConstantTable()
{
	for (unsigned int i=0;i<m_pool.size();i++)
	{
		delete m_pool[i];
	}
}


bool C_UTF8::isEqual(ConstantEntry * entry)
{
	return m_str==static_cast<C_UTF8*>(entry)->m_str;
}

void C_UTF8::writeData(JBFile * file)
{
	file->write((unsigned short)(m_str.length()));
	for (unsigned int i=0;i<m_str.length();i++)
	{
		file->write( *( (unsigned char*)&(m_str[i])   ) );
	}
}

bool C_STRING::isEqual(ConstantEntry * entry)
{
	return m_ind==static_cast<C_STRING*>(entry)->m_ind;
}

void C_STRING::writeData(JBFile * file)
{
	file->write(m_ind);
}

bool C_CLASS::isEqual(ConstantEntry * entry)
{
	return m_ind==static_cast<C_CLASS*>(entry)->m_ind;
}

void C_CLASS::writeData(JBFile * file)
{
	file->write(m_ind);
}


bool C_NAMEANDTYPE::isEqual(ConstantEntry * entry)
{
	return m_name==static_cast<C_NAMEANDTYPE*>(entry)->m_name
		&& m_descriptor==static_cast<C_NAMEANDTYPE*>(entry)->m_descriptor;
}

void C_NAMEANDTYPE::writeData(JBFile * file)
{
	file->write(m_name);
	file->write(m_descriptor);
}

bool C_ATTRIBUTEREF::isEqual(ConstantEntry * entry)
{
	return m_class==static_cast<C_ATTRIBUTEREF*>(entry)->m_class
		&& m_name_and_type==static_cast<C_ATTRIBUTEREF*>(entry)->m_name_and_type;
}

void C_ATTRIBUTEREF::writeData(JBFile * file)
{
	file->write(m_class);
	file->write(m_name_and_type);
}


bool C_FLOAT::isEqual(ConstantEntry * entry)
{
	return fabs(m_f-static_cast<C_FLOAT*>(entry)->m_f)<0.0001;
}
void C_FLOAT::writeData(JBFile * file)
{
	file->write(m_f);
}

bool C_INTEGER::isEqual(ConstantEntry * entry)
{
 return m_d==static_cast<C_INTEGER*>(entry)->m_d;
}

void C_INTEGER::writeData(JBFile * file)
{
	file->write(m_d);
}


unsigned short ConstantTable::createUTF8(const std::string & l)
{
 return  addConstant( new C_UTF8(l));
}

unsigned short ConstantTable::createStringLiteral(const std::string & l)
{
	return addConstant(new C_STRING( addConstant( new C_UTF8(l))));
}

unsigned short ConstantTable::createFloat(float f)
{
	return addConstant( new C_FLOAT(f) );
}

unsigned short ConstantTable::createInteger(int d)
{
	return addConstant( new C_INTEGER(d) );
}

unsigned short ConstantTable::createClass(const std::string & s)
{
	unsigned short added=addConstant( new C_UTF8(s));
	return addConstant(new C_CLASS(added ));
}

unsigned short ConstantTable::createNameAndType(const std::string & n, const std::string & d)
{
	return addConstant( new C_NAMEANDTYPE( addConstant( new C_UTF8(n) ),addConstant( new C_UTF8(d) )));
								
}

unsigned short ConstantTable::createFieldRef(const std::string & _class, const std::string & name, const std::string &d)
{
	return addConstant( new C_FIELDREF( createClass(_class), createNameAndType(name,d)));
}

unsigned short ConstantTable::createMethodRef(const std::string & _class, const std::string & name, const std::string &d)
{
	return addConstant( new C_METHODREF( createClass(_class), createNameAndType(name,d)));
}

unsigned short ConstantTable::createIMethodRef(const std::string & _class, const std::string & name, const std::string &d)
{
	return addConstant( new C_IMETHODREF( createClass(_class), createNameAndType(name,d)));
}

unsigned short ConstantTable::createMainConvertToArray()
{
	return createMethodRef("CONVERT","fromArgs","([Ljava/lang/String;)LARRAY;");
}

AttrInfo ConstantTable::createDefinition(const std::string & name, const std::string & dsc)
{
	return AttrInfo( createUTF8(name),createUTF8(dsc) ); 
}

void AttrInfo::write(JBFile * fl)
{
	fl->write(Name);
	fl->write(Descriptor);
}

AttrInfo ConstantTable::createMainDefinition()
{
  return createDefinition("main","([Ljava/lang/String;)V");
}

AttrInfo ConstantTable::createConstructor()
{
	return createDefinition("<init>","()V");
}

unsigned short ConstantTable::createConstructorRef( const std::string & parentClass)
{
	return createMethodRef(parentClass,"<init>","()V");
}

unsigned short ConstantTable::createGetBoolean()
{
	return createMethodRef("BOOLEAN","get","()Z");
}

unsigned short ConstantTable::createBooleanConstructor()
{
	return createMethodRef("BOOLEAN","<init>","(Z)V");
}

unsigned short ConstantTable::createIntegerConstructor()
{
	return createMethodRef("INTEGER","<init>","(I)V");
}

unsigned short ConstantTable::createRealConstructor()
{
	return createMethodRef("REAL","<init>","(F)V");
}

unsigned short ConstantTable::createCharacterConstructor()
{
	return createMethodRef("CHARACTER","<init>","(C)V");
}

unsigned short ConstantTable::createStringConstructor()
{
	return createMethodRef("STRING","<init>","(Ljava/lang/String;)V");
}

unsigned short ConstantTable::createBooleanClone()
{
	return createMethodRef("BOOLEAN","BOOLEANCLONE","()LBOOLEAN;");
}
unsigned short ConstantTable::createIntegerClone()
{
	return createMethodRef("INTEGER","INTEGERCLONE","()LINTEGER;");
}
unsigned short ConstantTable::createRealClone()
{
	return createMethodRef("REAL","REALCLONE","()LREAL;");
}
unsigned short ConstantTable::createCharacterClone()
{
	return createMethodRef("CHARACTER","CHARACTERCLONE","()LCHARACTER;");
}
unsigned short ConstantTable::createStringClone()
{
	return createMethodRef("STRING","STRINGCLONE","()LSTRING;");
}

unsigned short ConstantTable::createRefsEq()
{
	return createMethodRef("CONVERT","refsEq","(Ljava/lang/Object;Ljava/lang/Object;)LBOOLEAN;");
}

unsigned short ConstantTable::createRefsNeq()
{
	return createMethodRef("CONVERT","refsNeq","(Ljava/lang/Object;Ljava/lang/Object;)LBOOLEAN;");
}

unsigned short ConstantTable::createArrayClass()
{
	return createClass("ARRAY");
}

unsigned short ConstantTable::createArrayMake()
{
	return createMethodRef("ARRAY","ARRAYMAKE","(LINTEGER;)V");
}
unsigned short ConstantTable::createArrayConstructor()
{
	return this->createConstructorRef("ARRAY");
}
unsigned short ConstantTable::createArrayPut()
{
	return this->createMethodRef("ARRAY","ARRAYPUT","(LINTEGER;Ljava/lang/Object;)V");
}

void ConstantTable::print()
{
	printf("Pool table size: %d\n",m_pool.size()+1);
	for (unsigned int i=0;i<m_pool.size();i++)
	{
		printf("%d: ",i+1);
		m_pool[i]->print();
	}
}

void C_UTF8::print()
{
	printf("C_UTF8: %s\n",m_str.c_str());
}

void C_STRING::print()
{
  printf("C_STRING : %d\n",m_ind);
}

void C_FLOAT::print()
{
  printf("C_FLOAT : %f\n",m_f);
}

void C_INTEGER::print()
{
  printf("C_INTEGER : %d\n",m_d);
}

void C_CLASS::print()
{
  printf("C_CLASS : %d\n",m_ind);
}

void C_NAMEANDTYPE::print()
{
 printf("C_NAMEANDTYPE : %d %d\n",m_name,m_descriptor);
}

void C_ATTRIBUTEREF::print()
{
	this->printTag();
	printf(" : %d %d\n",m_class,m_name_and_type);
}

#define PRINTNAME(X) void X ::printTag()  { printf(#X); }

PRINTNAME(C_FIELDREF)
PRINTNAME(C_METHODREF)
PRINTNAME(C_IMETHODREF)
